﻿#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "TCPServer.h"
#include "TCPCilent.h"
using namespace std;
static void _on_new_connection(uv_stream_t *server, int status) {
	if (status < 0) {
		fprintf(stderr, "New connection error %s\n", uv_strerror(status));		
		return;
	}
	//((CTCPServer*)(server->data))->_OnNewSession(server);
}
CTCPServer::CTCPServer(uv_loop_t* loop) :_loop(loop)
{
}


CTCPServer::~CTCPServer()
{
	if (_server){ free(_server); _server=nullptr;}
}
static void _on_close(uv_handle_t* handle) {
	free(handle);
}
void CTCPServer::_OnNewSession(uv_stream_t*server, int status)
{
	if (status < 0) {
		fprintf(stderr, "New connection error %s\n", uv_strerror(status));
		return;
	}
	CTCPServer* svr = (CTCPServer*)(server->data);
	uv_tcp_t *client = (uv_tcp_t*)malloc(sizeof(uv_tcp_t));
	assert(client);
	uv_tcp_init(svr->_loop, client);
	if (uv_accept(server, (uv_stream_t*)client) == 0) {
		SessionPtr  session(Session::NewSeesion((uv_stream_t*)client));		
		session->OnRead([&](SessionPtr s, char* szByte, int len){
			svr->_sReadcb(s, szByte, len);
		});

		session->OnClose([&](SessionPtr s){		
			printf("tcp close\n");
			svr->_conn_cnt--;
			printf("client cnt %d\n", svr->_conn_cnt);
			map<unsigned long long, SessionPtr>::iterator key = svr->m_Mpsession.find(s->id);
			if (key != svr->m_Mpsession.end()){				
				svr->m_Mpsession.erase(s->id);
			}			
		});		
		svr->_conn_cnt++;
		svr->m_Mpsession.insert(make_pair(session->id, session));		
		printf("client cnt %d\n", svr->_conn_cnt);	
	}
	else {
		uv_close((uv_handle_t*)client, _on_close);
	}
	
}

void CTCPServer::StartServer(char* ip, size_t port)
{
	_server = (uv_tcp_t*)malloc(sizeof(uv_tcp_t));
	uv_tcp_init(_loop, _server);
	struct sockaddr_in addr;
	uv_ip4_addr(ip, port, &addr);
	uv_tcp_bind(_server, (const struct sockaddr*)&addr, 0);
	_server->data=this;
	uv_listen((uv_stream_t*)_server, 128, _OnNewSession);
	_ip = string(ip);
	_port = port;
}

void CTCPServer::StopServer()
{
	assert(_loop);	
	for (auto& itr : m_Mpsession)
	{
		((SessionPtr)(itr.second))->CloseSession();			
	}			
}
